﻿using System.Data.SqlTypes;
using System.Diagnostics;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using System;
using IVMPEditor.libs.SynBox;
using SynBoxNS;

namespace IVMPEditor
{
    public partial class Editor : Form
    {
        private static Timer t = new Timer();
        private static AutocompleteMenu AutoCompletePopup;
        private static List<AutocompleteItem> default_items = new List<AutocompleteItem>();
        private static List<AutocompleteItem> runtime_items = new List<AutocompleteItem>();
        private static string[] IVMP_EVENTS = "ScriptInit|ScriptExit|ServerPulse|ConsoleInput|ConsoleOutput|ServerQueryReceived|ScriptError|WebRequest|PlayerRequestNameChange|PlayerConnect|PlayerJoin|PlayerDisconnect|PlayerText|PlayerCommand|PlayerSpawn|PlayerDeath|PlayerChangeState|PlayerSyncReceived|PlayerOnFootSyncReceived|PlayerInCarSyncReceived|PlayerPassengerSyncReceived|PlayerEmptyVehicleSyncReceived|PlayerAimSyncReceived|PlayerChangePadState|PlayerKeyPress|VehicleEntryRequest|VehicleEntryCancelled|VehicleEntryComplete|VehicleExitRequest|VehicleExitComplete|VehicleForcefulExit|PlayerShot|HeadMove|VehicleCreate|VehicleDelete|VehicleDamage|VehicleDeath|VehicleRespawn|ObjectCreate|ObjectDelete|PlayerEnterCheckpoint|PlayerLeaveCheckpoint|BlipCreate|BlipDelete|ActorCreate|ActorDelete|ScriptInit|ScriptExit|FrameRender|KeyPress|PlayerConnect|PlayerSpawn|PlayerCommand|ButtonClick|WindowClose".Split('|');
        private static string[] IVMP_METHODS =
            "log|addRule|setRule|removeRule|shutdown|setServerPassword|getServerPassword|getPlayerCount|getPlayerSlots|getTickCount|togglePayAndSpray|toggleAutoAim|sendConsoleInput|setHostname|getHostname|getPlayers|getConfig|toggleFrequentEvents|areFrequentEventsEnabled|getWeaponName|getRule|isPlayerConnected|setPlayerSpawnLocation|getPlayerName|setPlayerHealth|getPlayerHealth|setPlayerCoordinates|getPlayerCoordinates|setPlayerHeading|getPlayerHeading|setPlayerModel|getPlayerModel|setPlayerTime|setPlayerGravity|sendPlayerMessage|sendMessageToAll|getPlayerVehicleId|isPlayerOnFoot|isPlayerInVehicle|togglePlayerPayAndSpray|togglePlayerAutoAim|togglePlayerControls|isPlayerSpawned|getPlayerIp|banPlayer|kickPlayer|getPlayerArmour|setPlayerArmour|togglePlayerPhysics|setPlayerMoney|getPlayerMoney|givePlayerMoney|resetPlayerMoney|setPlayerVelocity|getPlayerVelocity|togglePlayerFrozen|getPlayerState|setPlayerWantedLevel|isPlayerInAnyVehicle|warpPlayerIntoVehicle|removePlayerFromVehicle|givePlayerWeapon|removePlayerWeapons|getPlayerAmmo|getPlayerWeapon|setCameraBehindPlayer|getPlayerSeatId|togglePlayerHud|togglePlayerRadar|togglePlayerNames|togglePlayerAreaNames|setPlayerInterior|getPlayerInterior|getEmptyPlayerPadState|getPlayerPadState|givePlayerHelmet|removePlayerHelmet|setPlayerWeather|getPlayerPreviousPadState|setPlayerColor|getPlayerColor|setPlayerName|getPlayerPing|setPlayerClothes|getPlayerClothes|resetPlayerClothes|getPlayerSerial|setPlayerDucking|setPlayerInvincible|respawnPlayer|setPlayerCameraPos|setPlayerCameraLookAt|resetPlayerCamera|attachPlayerCameraToPlayer|attachPlayerCameraToVehicle|setPlayerVehicleFollowMode|setPlayerVehicleFollowOffset|togglePlayerHelmet|triggerPlayerPoliceReport|triggerPlayerGameSound|triggerPlayerMissionSound|forcePlayerPlayAnimation|requestPlayerAnimations|fadePlayerScreenIn|fadePlayerScreenOut|blockPlayerDropWeaponsAtDeath|blockPlayerWeaponScroll|displayHudNotification|setPlayerAmmoInClip|setPlayerAmmo|setPlayerUseMobilePhone|sayPlayerSpeech|letPlayerDriveAutomaticAtCoords|createVehicle|deleteVehicle|setVehicleCoordinates|getVehicleCoordinates|isVehicleValid|getVehicleModel|setVehicleColor|getVehicleColor|setVehicleHealth|getVehicleHealth|setVehicleVelocity|getVehicleVelocity|getVehicleName|getVehicleRotation|setVehicleRotation|isVehicleOccupied|getVehicleOccupants|setVehicleDirtLevel|soundVehicleHorn|setVehicleSirenState|setVehicleLocked|getVehicleLocked|setVehicleIndicators|getVehicleIndicators|setVehicleComponent|getVehicleComponents|resetVehicleComponents|setVehicleVariation|getVehicleVariation|getVehicleDirtLevel|getVehicleSirenState|getVehicleEngineState|setVehicleEngineState|setVehicleLights|getVehicleLights|setVehicleTaxiLights|getVehicleTaxiLights|repairVehicleWindows|repairVehicleWheels|controlCarDoors|markVehicleAsActorVehicle|setVehicleAlarm|createObject|deleteObject|getObjectModel|setObjectCoordinates|getObjectCoordinates|setObjectRotation|getObjectRotation|attachObjectToVehicle|attachObjectToPlayer|createCheckpoint|deleteCheckpoint|showCheckpointForPlayer|hideCheckpointForPlayer|showCheckpointForAll|hideCheckpointForAll|setCheckpointType|getCheckpointType|setCheckpointPosition|getCheckpointPosition|setCheckpointTargetPosition|getCheckpointTargetPosition|setCheckpointRadius|getCheckpointRadius|addEvent|callEvent|removeEvent|triggerClientEvent|triggerServerEvent|getDistanceBetweenPoints2D|getDistanceBetweenPoints3D|isPointInCircle|isPointInTube|isPointInBall|isPointInArea|isPointInCuboid|isPointInPolygon|displayPlayerText|displayTextForAll|displayPlayerInfoText|displayInfoTextForAll|createBlip|deleteBlip|setBlipCoordinates|getBlipCoordinates|setBlipColor|getBlipColor|setBlipSize|getBlipSize|toggleBlipRoute|toggleBlipShortRange|setBlipName|getBlipName|switchBlipIcon|switchBlipIconForPlayer|createPlayerBlip|deletePlayerBlip|togglePlayerBlipShortRange|togglePlayerBlipDisplay|createActor|deleteActor|setActorCoordinates|setActorHeading|actorWalkToCoordinatesForPlayer|isActorValid|getActorModel|getActorCount|getActorCoordinates|getActorHeading|setActorName|getActorName|toggleActorNametag|setActorNametagColor|getActorNametagColor|toggleActorFrozen|toggleActorHelmet|warpActorIntoVehicle|removeActorFromVehicle|deleteAllActors|isActorOnFoot|getActorSeatId|forceAnimationAtActor|toggleActorBlip|sayActorSpeech|driveActorToCoordinates|createPickup|deletePickup|getPickupModel|getPickupType|getPickupValue|setPickupCoordinates|getPickupCoordinates|setPickupRotation|getPickupRotation|setPickupValue|md5|md5File|timer|setTraditionalBehavior|kill|isActive|getScripts|getClientScripts|getClientResources|getScriptName|loadScript|unloadScript|reloadScript|loadClientScript|unloadClientScript|reloadClientScript|loadClientResource|unloadClientResource|reloadClientResource|setWeather|getWeather|date|setTime|getTime|setMinuteDuration|getMinuteDuration|setDayOfWeek|getDayOfWeek|setTrafficLightsState|getTrafficLightsState|setTrafficLightsLocked|areTrafficLightsLocked|setTrafficLightsPhaseDuration|getTrafficLightsPhaseDuration|resetTrafficLightsPhaseDuration|createFire|deleteFire|createExplosion|forceWind|drawLightWithRange|mysql|connect|connected|disconnect|error|escape|query|query_insertid|query_assoc|query_assoc_single|query_affected_rows|create_table|addChatMessage|getClientScripts|getScriptName|toggleChatWindow|isChatWindowVisible|getCurrentAreaName|getCurrentStreetName|getFPS|isGameFocused|setRadarZoom|getScreenPositionFromWorldPosition|getActorPosition|addEvent|callEvent|removeEvent|triggerClientEvent|triggerServerEvent|getDistanceBetweenPoints2D|getDistanceBetweenPoints3D|isPointInCircle|isPointInTube|isPointInBall|isPointInArea|isPointInCuboid|isPointInPolygon|isPlayerConnected|getLocalPlayer|getPlayerName|getPlayerHealth|getPlayerArmour|getPlayerCoordinates|getPlayerVehicleId|getPlayerSeatId|isPlayerOnFoot|getPlayerModel|isPlayerSpawned|getPlayerHeading|getPlayerMoney|getPlayerState|getPlayerVelocity|getPlayerAmmo|getPlayerInterior|getPlayerPadState|isPlayerJackingAVehicle|getPlayerWeaponSlot|getPlayerAmmoInClip|isVehicleValid|getVehicleCoordinates|getVehicleHeading|getVehicleColor|getVehicleModel|getVehicleHealth|getVehicleEngineHealth|getVehicleVelocity|getVehicleLocked|getVehicleName|getVehicleDirtLevel|isVehicleOccupied|getVehicleOccupants|getVehicleSirenState|getVehicleEngineState|guiShowMessageBox|guiToggleCursor|isCursorVisible|guiGetScreenSize|guiDrawRectangle|getScreenPositionFromWorldPosition|GUIFont|GUIText|GUIWindow|GUIButton|GUIEditBox|GUICheckBox|GUIImage|GUIElement|createAudioFromFile|createAudioFromUrl|sendTypeMessage|sendTypeMessageToAll|showPlayerDialog"
                .Split('|');
        private static string[] AC_Snippets = { "if(^){\n;\n}", "if(^){\n;\n}\nelse\n{\n;\n}", "if(^){\n;\n}\nelse\n{\n;\n}\nelse if(){\n;\n}", "for(^;;){\n;\n}", "while(^){\n;\n}", "switch(^){\n\n}" };
        private static string[] AC_DeclarationSnippets = { "function ^ (){\n\n}", "function(){\n\t\t\t^\n}", "function(){ ^ }" };
        private static string file = null;

        public Editor()
        {
            InitializeComponent();
        }

        private List<T> Concat<T>(List<T> A, List<T> B)
        {
            var result = new List<T>();
            foreach (T i in A)
                result.Add(i);
            foreach (T i in B)
                result.Add(i);
            return result;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            scriptExplorer.BackColor = Color.FromArgb(41, 49, 52);
            t.Interval = 1000;
            t.Tick += TOnTick;
            t.Enabled = true;
            AutoCompletePopup = new AutocompleteMenu(synbox) {BackColor = Color.Transparent};
            AutoCompletePopup.Items.ImageList = autocomplete;
            AutoCompletePopup.SearchPattern = @"[\w\.:=!<>]";
            AutoCompletePopup.ImageList = autocomplete;


            foreach (var item in IVMP_METHODS)
                default_items.Add(new AutocompleteItem(item) { ImageIndex = 4 });
            foreach (var item in IVMP_EVENTS)
                default_items.Add(new AutocompleteItem(item) { ImageIndex = 2 });
            
            foreach (var autocompleteItem in default_items)
                scriptExplorer.Nodes.Add("", autocompleteItem.Text, autocompleteItem.ImageIndex,
                                         autocompleteItem.ImageIndex);

            foreach (var item in AC_Snippets)
                default_items.Add(new SnippetAutocompleteItem(item) { ImageIndex = 9 });
            foreach (var item in AC_DeclarationSnippets)
                default_items.Add(new DeclarationSnippet(item) { ImageIndex = 5 });

            

            default_items.Add(new InsertSpaceSnippet());
            default_items.Add(new InsertSpaceSnippet(@"^(\w+)([=<>!:]+)(\w+)$"));
            default_items.Add(new InsertEnterSnippet());

            AutoCompletePopup.Items.SetAutocompleteItems(default_items);

            string[] args = Environment.GetCommandLineArgs();
            if (args.Length > 1)
            {
                file = args[1];
                synbox.Text = File.ReadAllText(file);
            }
        }

        private void TOnTick(object sender, EventArgs eventArgs)
        {
            runtime_items.Clear();
            foreach (Match match in Regex.Matches(synbox.Text, @"class ([a-zA-Z0-9_]+)(.)", RegexOptions.IgnoreCase))
                runtime_items.Add(new AutocompleteItem(match.Groups[1].Captures[0].Value.Trim()) { ImageIndex = 7 });
            foreach (Match match in Regex.Matches(synbox.Text, @"enum ([a-zA-Z0-9_]+)(.)", RegexOptions.IgnoreCase))
                runtime_items.Add(new AutocompleteItem(match.Groups[1].Captures[0].Value.Trim()) { ImageIndex = 8 });
            foreach (Match match in Regex.Matches(synbox.Text, @"function ([a-zA-Z0-9_]+)\(([^\)]|)\)", RegexOptions.IgnoreCase))
                runtime_items.Add(new FunctionSnippet(match.Groups[1].Captures[0].Value.Trim()) { ImageIndex = 3 });
            foreach (Match match in Regex.Matches(synbox.Text, @"const ([a-zA-Z0-9_]+)(.*|)\;", RegexOptions.IgnoreCase))
                runtime_items.Add(new AutocompleteItem(match.Groups[1].Captures[0].Value.Trim()) { ImageIndex = 10 });
            foreach (Match match in Regex.Matches(synbox.Text, @"local ([a-zA-Z0-9_]+)(.*|)\;", RegexOptions.IgnoreCase))
                runtime_items.Add(new AutocompleteItem(match.Groups[1].Captures[0].Value.Trim()) { ImageIndex = 3 });
            
            AutoCompletePopup.Items.SetAutocompleteItems(Concat(runtime_items, default_items));
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure want to create new script?", "New script", MessageBoxButtons.YesNo,
                                MessageBoxIcon.Question) == DialogResult.Yes)
            {
                synbox.Text = "";
                file = null;
            }
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                file = saveFileDialog.FileName;
                File.WriteAllText(file, synbox.Text);
            }
        }

        private void scriptExplorer_DoubleClick(object sender, EventArgs e)
        {

        }

        private void scriptExplorer_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (scriptExplorer.SelectedNode == null) return;
            var insertText = scriptExplorer.SelectedNode.Text;
            var selectionIndex = synbox.SelectionStart;
            synbox.Text = synbox.Text.Insert(selectionIndex, insertText);
            synbox.SelectionStart = selectionIndex + insertText.Length;
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                file = openFileDialog.FileName;
                synbox.Text = File.ReadAllText(file);
            }
        }

        private void synbox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.S && e.Control)
            {
                File.WriteAllText(file, synbox.Text);
            }
        }
    }
}
